﻿using System.Diagnostics;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using CodeContrib.Web.Routing;

namespace CodeContrib.Web.Mvc.Routing
{
	public static class RoutingExtensions
	{
		[DebuggerStepThrough]
		public static void IgnoreStaticRoutes(this RouteCollection routes)
		{
			// Turns off the unnecessary file exists check.
			routes.RouteExistingFiles = true;

			// Ignore files.
			routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
			routes.IgnoreRoute("{resource}.css/{*pathInfo}");
			routes.IgnoreRoute("{resource}.gif/{*pathInfo}");
			routes.IgnoreRoute("{resource}.htm/{*pathInfo}");
			routes.IgnoreRoute("{resource}.html/{*pathInfo}");
			routes.IgnoreRoute("{resource}.ico/{*pathInfo}");
			routes.IgnoreRoute("{resource}.jpg/{*pathInfo}");
			routes.IgnoreRoute("{resource}.js/{*pathInfo}");
			routes.IgnoreRoute("{resource}.png/{*pathInfo}");
			routes.IgnoreRoute("{resource}.txt/{*pathInfo}");

			routes.IgnoreRoute("{*allaspx}", new
				                                 {
					                                 allaspx = @".*\.aspx(/.*)?"
				                                 });

			// Ignore the content and script files.
			routes.IgnoreRoute("content/{*pathInfo}");
			routes.IgnoreRoute("scripts/{*pathInfo}");

			// Ignore favicon.
			routes.IgnoreRoute("{*favicon}", new
				                                 {
					                                 favicon = @"(.*/)?favicon.([iI][cC][oO]|[gG][iI][fF])(/.*)?"
				                                 });
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url)
		{
			return MapLowercaseRoute(routes, name, url, null /* defaults */, null /* constraints */);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, object defaults)
		{
			return MapLowercaseRoute(routes, name, url, defaults, null /* constraints */);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, object defaults, object constraints)
		{
			return MapLowercaseRoute(routes, name, url, defaults, constraints, null /* namespaces */);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, string[] namespaces)
		{
			return MapLowercaseRoute(routes, name, url, null /* defaults */, null /* constraints */, namespaces);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
		{
			return MapLowercaseRoute(routes, name, url, defaults, null /* constraints */, namespaces);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
		{
			Guard.NotNull(routes, "routes");
			Guard.NotNull(url, "url");

			Route route = new LowercaseRoute(url, defaults.ToRouteValueDictionary(), constraints.ToRouteValueDictionary(), new MvcRouteHandler());

			return MapRoute(routes, name, route, namespaces);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this AreaRegistrationContext context, string name, string url)
		{
			return MapLowercaseRoute(context, name, url, null /* defaults */, null /* constraints */);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this AreaRegistrationContext context, string name, string url, object defaults)
		{
			return MapLowercaseRoute(context, name, url, defaults, null /* constraints */);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this AreaRegistrationContext context, string name, string url, object defaults, object constraints)
		{
			return MapLowercaseRoute(context, name, url, defaults, constraints, null /* namespaces */);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this AreaRegistrationContext context, string name, string url, string[] namespaces)
		{
			return MapLowercaseRoute(context, name, url, null /* defaults */, null /* constraints */, namespaces);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this AreaRegistrationContext context, string name, string url, object defaults, string[] namespaces)
		{
			return MapLowercaseRoute(context, name, url, defaults, null /* constraints */, namespaces);
		}

		[DebuggerStepThrough]
		public static Route MapLowercaseRoute(this AreaRegistrationContext context, string name, string url, object defaults, object constraints, string[] namespaces)
		{
			Guard.NotNull(context, "context");
			Guard.NotNull(url, "url");

			Route route = new LowercaseRoute(url, defaults.ToRouteValueDictionary(), constraints.ToRouteValueDictionary(), new MvcRouteHandler());

			return MapRoute(context, name, route, namespaces);
		}

		[DebuggerStepThrough]
		public static void MapPagingAndSortingRoutes(this RouteCollection routes, string controllerName, string actionName)
		{
			MapPagingAndSortingRoutes(routes, controllerName, actionName, null);
		}

		[DebuggerStepThrough]
		public static void MapPagingAndSortingRoutes(this RouteCollection routes, string controllerName, string actionName, string[] namespaces)
		{
			routes.MapLowercaseRoute("HomePaging", "({page}-{size})", new
				                                                          {
					                                                          controller = controllerName,
					                                                          action = actionName
				                                                          }, null, namespaces);

			routes.MapLowercaseRoute("HomePagingSorting", "({page}-{size}-{sort}-{direction})", new
				                                                                                    {
					                                                                                    controller = controllerName,
					                                                                                    action = actionName
				                                                                                    }, null, namespaces);

			routes.MapLowercaseRoute("DefaultPaging", "{controller}/{action}/({page}-{size})", new
				                                                                                   {
					                                                                                   controller = "Home",
					                                                                                   action = "Index"
				                                                                                   }, null, namespaces);

			routes.MapLowercaseRoute("DefaultPagingId", "{controller}/{action}/{id}/({page}-{size})", new
				                                                                                          {
					                                                                                          controller = "Home",
					                                                                                          action = "Index",
					                                                                                          id = UrlParameter.Optional
				                                                                                          }, null, namespaces);

			routes.MapLowercaseRoute("DefaultPagingSorting", "{controller}/{action}/({page}-{size}-{sort}-{direction})", new
				                                                                                                             {
					                                                                                                             controller = "Home",
					                                                                                                             action = "Index"
				                                                                                                             }, null, namespaces);

			routes.MapLowercaseRoute("DefaultPagingSortingId", "{controller}/{action}/{id}/({page}-{size}-{sort}-{direction})", new
				                                                                                                                    {
					                                                                                                                    controller = "Home",
					                                                                                                                    action = "Index",
					                                                                                                                    id = UrlParameter.Optional
				                                                                                                                    }, null, namespaces);
		}

		internal static Route MapRoute(this RouteCollection routes, string name, Route route, string[] namespaces)
		{
			if (namespaces != null
			    && namespaces.Length > 0)
			{
				route.DataTokens["Namespaces"] = namespaces;
			}

			routes.Add(name, route);

			return route;
		}

		internal static Route MapRoute(this AreaRegistrationContext context, string name, Route route, string[] namespaces)
		{
			if (namespaces == null
			    && context.Namespaces != null)
			{
				namespaces = context.Namespaces.ToArray();
			}

			route.DataTokens["area"] = context.AreaName;

			var useNamespaceFallback = (namespaces == null || namespaces.Length == 0);
			route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback;

			MapRoute(context.Routes, name, route, namespaces);

			return route;
		}

		[DebuggerStepThrough]
		public static void MapTenantPagingAndSortingRoutes(this RouteCollection routes, string controllerName, string actionName)
		{
			MapTenantPagingAndSortingRoutes(routes, controllerName, actionName, null);
		}

		[DebuggerStepThrough]
		public static void MapTenantPagingAndSortingRoutes(this RouteCollection routes, string controllerName, string actionName, string[] namespaces)
		{
			routes.MapTenantRoute("HomeTenantPaging", "{tenant}/({page}-{size})", new
				                                                                      {
					                                                                      tenant = "default",
					                                                                      controller = controllerName,
					                                                                      action = actionName
				                                                                      }, new
					                                                                         {
						                                                                         tenant = new TenantRouteConstraint()
					                                                                         }, namespaces);

			routes.MapTenantRoute("HomeTenantPagingSorting", "{tenant}/({page}-{size}-{sort}-{direction})", new
				                                                                                                {
					                                                                                                tenant = "default",
					                                                                                                controller = controllerName,
					                                                                                                action = actionName
				                                                                                                }, new
					                                                                                                   {
						                                                                                                   tenant = new TenantRouteConstraint()
					                                                                                                   }, namespaces);

			routes.MapTenantRoute("DefaultTenantPaging", "{tenant}/{controller}/{action}/({page}-{size})", new
				                                                                                               {
					                                                                                               tenant = "default",
					                                                                                               controller = "Home",
					                                                                                               action = "Index"
				                                                                                               }, new
					                                                                                                  {
						                                                                                                  tenant = new TenantRouteConstraint()
					                                                                                                  }, namespaces);

			routes.MapTenantRoute("DefaultTenantPagingId", "{tenant}/{controller}/{action}/{id}/({page}-{size})", new
				                                                                                                      {
					                                                                                                      tenant = "default",
					                                                                                                      controller = "Home",
					                                                                                                      action = "Index",
					                                                                                                      id = UrlParameter.Optional
				                                                                                                      }, new
					                                                                                                         {
						                                                                                                         tenant = new TenantRouteConstraint()
					                                                                                                         }, namespaces);

			routes.MapTenantRoute("DefaultTenantPagingSorting", "{tenant}/{controller}/{action}/({page}-{size}-{sort}-{direction})", new
				                                                                                                                         {
					                                                                                                                         tenant = "default",
					                                                                                                                         controller = "Home",
					                                                                                                                         action = "Index"
				                                                                                                                         }, new
					                                                                                                                            {
						                                                                                                                            tenant = new TenantRouteConstraint()
					                                                                                                                            }, namespaces);

			routes.MapTenantRoute("DefaultTenantPagingSortingId", "{tenant}/{controller}/{action}/{id}/({page}-{size}-{sort}-{direction})", new
				                                                                                                                                {
					                                                                                                                                tenant = "default",
					                                                                                                                                controller = "Home",
					                                                                                                                                action = "Index",
					                                                                                                                                id = UrlParameter.Optional
				                                                                                                                                }, new
					                                                                                                                                   {
						                                                                                                                                   tenant = new TenantRouteConstraint()
					                                                                                                                                   }, namespaces);
		}

		[DebuggerStepThrough]
		public static Route MapTenantRoute(this RouteCollection routes, string name, string url)
		{
			return MapTenantRoute(routes, name, url, null /* defaults */, null /* constraints */);
		}

		[DebuggerStepThrough]
		public static Route MapTenantRoute(this RouteCollection routes, string name, string url, object defaults)
		{
			return MapTenantRoute(routes, name, url, defaults, null /* constraints */);
		}

		[DebuggerStepThrough]
		public static Route MapTenantRoute(this RouteCollection routes, string name, string url, object defaults, object constraints)
		{
			return MapTenantRoute(routes, name, url, defaults, constraints, null /* namespaces */);
		}

		[DebuggerStepThrough]
		public static Route MapTenantRoute(this RouteCollection routes, string name, string url, string[] namespaces)
		{
			return MapTenantRoute(routes, name, url, null /* defaults */, null /* constraints */, namespaces);
		}

		[DebuggerStepThrough]
		public static Route MapTenantRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
		{
			return MapTenantRoute(routes, name, url, defaults, null /* constraints */, namespaces);
		}

		[DebuggerStepThrough]
		public static Route MapTenantRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
		{
			Route route = new TenantRoute(url, defaults.ToRouteValueDictionary(), constraints.ToRouteValueDictionary(), new MvcRouteHandler());

			return MapRoute(routes, name, route, namespaces);
		}
	}
}